home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / b / b.lha / B / src / bed / edit.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-11-24  |  7.2 KB  |  383 lines

  1. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
  2. static char rcsid[] = "$Header: edit.c,v 2.5 85/08/22 16:01:43 timo Exp $";
  3.  
  4. /*
  5.  * B editor -- Read unit from file.
  6.  */
  7.  
  8. #include <ctype.h>
  9.  
  10. #include "b.h"
  11. #include "feat.h"
  12. #include "erro.h"
  13. #include "bobj.h"
  14. #include "node.h"
  15. #include "tabl.h"
  16. #include "gram.h"
  17. #include "supr.h"
  18. #include "queu.h"
  19.  
  20. string unixerror();
  21.  
  22. /*
  23.  * TABSIZE sets the number of spaces equivalent to a tab character
  24.  * read from the input; INDENT sets the number of spaces for one indentation
  25.  * level.
  26.  * The definitions here are unrelated to the definition of TABS
  27.  * in eval.h (used by show.c and eval.c).  The definition here only
  28.  * defines how many spaces must be equivalenced to a tab stop when read
  29.  * from a file; tab stops must be caused by editing a unit with another
  30.  * editor (vi, ed, ex, emacs), since "save.c" always writes spaces,
  31.  * not tabs.  The value '4' is best suited for people at the CWI who
  32.  * may have workspaces with units edited with the previous version of
  33.  * the B editor, which emitted a tab for each indentation level (and
  34.  * assumed 4 spaces for a tab stop on input).
  35.  *
  36.  * The variables 'spacesused' and 'tabsused' are kept to see if mixed use
  37.  * of spaces and tabs was made; this can cause indentation errors.
  38.  */
  39.  
  40. #ifdef CWI
  41. #define TABSIZE 4
  42. #else
  43. #define TABSIZE 8
  44. #endif
  45.  
  46. #define INDENT 4
  47.  
  48. Hidden bool spacesused;
  49. Hidden bool tabsused;
  50.  
  51.  
  52. /*
  53.  * Read (edit) parse tree from file into the focus.
  54.  * Rather ad hoc, we use ins_string for each line
  55.  * and do some magic tricks to get the indentation right
  56.  * (most of the time).
  57.  * If line > 0, position the focus at that line, if possible;
  58.  * otherwise the focus is left at the end of the inserted text.
  59.  */
  60.  
  61. Visible bool
  62. edit(ep, filename, line)
  63.     register environ *ep;
  64.     string filename;
  65.     int line;
  66. {
  67.     int lines = 0;
  68.     register FILE *fp = fopen(filename, "r");
  69.     register int c;
  70.     char buf[BUFSIZ];
  71.     auto string cp;
  72.     auto queue q = Qnil;
  73.  
  74.     if (!fp) {
  75.         error("%s", unixerror(filename));
  76.         return No;
  77.     }
  78.  
  79.     spacesused = tabsused = No;
  80.     do {
  81.         do {
  82.             for (cp = buf; cp < buf + sizeof buf - 1; ++cp) {
  83.                 c = getc(fp);
  84.                 if (c == EOF || c == '\n')
  85.                     break;
  86.                 if (c < ' ' || c >= 0177)
  87.                     c = ' ';
  88.                 *cp = c;
  89.             }
  90.             if (cp > buf) {
  91.                 *cp = 0;
  92.                 if (!ins_string(ep, buf, &q, 0) || !emptyqueue(q)) {
  93.                     qrelease(q);
  94.                     error(EDIT_BAD);
  95.                     fclose(fp);
  96.                     return No;
  97.                 }
  98.                 qrelease(q);
  99.             }
  100.         } while (c != EOF && c != '\n');
  101.         ++lines;
  102.         if (c != EOF && !editindentation(ep, fp)) {
  103.             fclose(fp);
  104.             return No;
  105.         }
  106.     } while (c != EOF);
  107.     fclose(fp);
  108.     if (ep->mode == FHOLE || ep->mode == VHOLE && (ep->s1&1)) {
  109.         cp = "";
  110.         soften(ep, &cp, 0);
  111.     }
  112.     if (lines > 1 && line > 0) {
  113.         gotoyx(ep, line-1, 0);
  114.         oneline(ep);
  115.     }
  116.     if (spacesused && tabsused)
  117.         error(EDIT_TABS);
  118.     return Yes;
  119. }
  120.  
  121.  
  122. /*
  123.  * Do all the footwork required to get the indentation proper.
  124.  */
  125.  
  126. Hidden Procedure
  127. editindentation(ep, fp)
  128.     register environ *ep;
  129.     register FILE *fp;
  130. {
  131.     register int tabs = 0;
  132.     auto int level;
  133.     register int c;
  134.  
  135.     while ((c = getc(fp)) == ' ' || c == '\t') {
  136.         if (c == ' ') {
  137.             spacesused = Yes;
  138.             ++tabs;
  139.         }
  140.         else {
  141.             tabsused = Yes;
  142.             tabs = (tabs/TABSIZE + 1)*TABSIZE;
  143.         }
  144.     }
  145.     ungetc(c, fp);
  146.     if (c == EOF || c == '\n')
  147.         return Yes;
  148.     tabs = (tabs+(INDENT/2))/INDENT; /* Transform to tab stops */
  149.     if (!ins_newline(ep)) {
  150. #ifndef NDEBUG
  151.         debug("[Burp! Can't insert a newline.]");
  152. #endif NDEBUG
  153.         return No;
  154.     }
  155.     level = Level(ep->focus);
  156.     for (; tabs < level; --level) {
  157.         if (!ins_newline(ep)) {
  158. #ifndef NDEBUG
  159.             debug("[Burp, burp! Can't decrease indentation.]");
  160. #endif NDEBUG
  161.             return No;
  162.         }
  163.     }
  164.     fixit(ep);
  165.     return Yes;
  166. }
  167.  
  168.  
  169. /* ------------------------------------------------------------ */
  170.  
  171. #ifdef SAVEBUF
  172.  
  173. /*
  174.  * Read the next non-space character.
  175.  */
  176.  
  177. Hidden int
  178. skipsp(fp)
  179.     register FILE *fp;
  180. {
  181.     register int c;
  182.  
  183.     do {
  184.         c = getc(fp);
  185.     } while (c == ' ');
  186.     return c;
  187. }
  188.  
  189.  
  190. /*
  191.  * Read a text in standard B format when the initial quote has already
  192.  * been read.
  193.  */
  194.  
  195. Hidden value
  196. readtext(fp, quote)
  197.     register FILE *fp;
  198.     register char quote;
  199. {
  200.     auto value v = Vnil;
  201.     char buf[BUFSIZ];
  202.     register string cp = buf;
  203.     register int c;
  204.     auto int i;
  205.  
  206.     for (; ; ++cp) {
  207.         c = getc(fp);
  208.         if (!isascii(c) || c != ' ' && !isprint(c)) {
  209.             if (c == EOF)
  210.                 debug("readtext: EOF");
  211.             else
  212.                 debug("readtext: bad char (0%02o)", c);
  213.             release(v);
  214.             return Vnil; /* Bad character or EOF */
  215.         }
  216.         if (c == quote) {
  217.             c = getc(fp);
  218.             if (c != quote) {
  219.                 ungetc(c, fp);
  220.                 break;
  221.             }
  222.         }
  223.         else if (c == '`') {
  224.             c = skipsp(fp);
  225.             if (c == '$') {
  226.                 i = 0;
  227.                 if (fscanf(fp, "%d", &i) != 1
  228.                     || i == 0 || !isascii(i)) {
  229.                     debug("readtext: error in conversion");
  230.                     release(v);
  231.                     return Vnil;
  232.                 }
  233.                 c = skipsp(fp);
  234.             }
  235.             else
  236.                 i = '`';
  237.             if (c != '`') {
  238.                 if (c == EOF)
  239.                     debug("readtext: EOF in conversion");
  240.                 else
  241.                     debug("readtext: bad char in conversion (0%o)", c);
  242.                 release(v);
  243.                 return Vnil;
  244.             }
  245.             c = i;
  246.         }
  247.         if (cp >= &buf[sizeof buf - 1]) {
  248.             *cp = 0;
  249.             if (v)
  250.                 concato(&v, buf);
  251.             else
  252.                 v = mk_text(buf);
  253.             cp = buf;
  254.         }
  255.         *cp = c;
  256.     }
  257.     *cp = 0;
  258.     if (!v)
  259.         return mk_text(buf);
  260.     concato(&v, buf);
  261.     return v;
  262. }
  263.  
  264.  
  265. Hidden int
  266. readsym(fp)
  267.     register FILE *fp;
  268. {
  269.     register int c;
  270.     char buf[100];
  271.     register string bufp;
  272.  
  273.     for (bufp = buf; ; ++bufp) {
  274.         c = getc(fp);
  275.         if (c == EOF)
  276.             return -1;
  277.         if (!isascii(c) || !isalnum(c) && c != '_') {
  278.             if (ungetc(c, fp) == EOF)
  279.                 syserr("readsym: ungetc failed");
  280.             break;
  281.         }
  282.         *bufp = c;
  283.     }
  284.     *bufp = 0;
  285.     if (isdigit(buf[0]))
  286.         return atoi(buf);
  287.     if (strcmp(buf, "Required") == 0) /***** Compatibility hack *****/
  288.         return Hole;
  289.     return nametosym(buf);
  290. }
  291.  
  292.  
  293. /*
  294.  * Read a node in internal format (recursively).
  295.  * Return nil pointer if EOF or error.
  296.  */
  297.  
  298. Hidden node
  299. readnode(fp)
  300.     FILE *fp;
  301. {
  302.     int c;
  303.     int nch;
  304.     node ch[MAXCHILD];
  305.     node n;
  306.     int sym;
  307.  
  308.     c = skipsp(fp);
  309.     switch (c) {
  310.     case EOF:
  311.         return Nnil; /* EOF hit */
  312.  
  313.     case '(':
  314.         sym = readsym(fp);
  315.         if (sym < 0) {
  316.             debug("readnode: missing symbol");
  317.             return Nnil; /* No number as first item */
  318.         }
  319.         if (sym < 0 || sym > Hole) {
  320.             debug("readnode: bad symbol (%d)", sym);
  321.             return Nnil;
  322.         }
  323.         nch = 0;
  324.         while ((c = skipsp(fp)) == ',' && nch < MAXCHILD) {
  325.             n = readnode(fp);
  326.             if (!n) {
  327.                 for (; nch > 0; --nch)
  328.                     noderelease(ch[nch-1]);
  329.                 return Nnil; /* Error encountered in child */
  330.             }
  331.             ch[nch] = n;
  332.             ++nch;
  333.         }
  334.         if (c != ')') {
  335.             if (c == ',')
  336.                 debug("readnode: node too long (sym=%d)", sym);
  337.             else
  338.                 debug("readnode: no ')' where expected (sym=%d)", sym);
  339.             for (; nch > 0; --nch)
  340.                 noderelease(ch[nch-1]);
  341.             return Nnil; /* Not terminated with ')' or too many children */
  342.         }
  343.         if (nch == 0)
  344.             return gram(sym); /* Saves space for Optional/Hole nodes */
  345.         return newnode(nch, sym, ch);
  346.  
  347.     case '\'':
  348.     case '"':
  349.         return (node) readtext(fp, c);
  350.  
  351.     default:
  352.         debug("readnode: bad initial character");
  353.         return Nnil; /* Bad initial character */
  354.     }
  355. }
  356.  
  357.  
  358. /*
  359.  * Read a node written in a more or less internal format.
  360.  */
  361.  
  362. Visible value
  363. editqueue(filename)
  364.     string filename;
  365. {
  366.     register FILE *fp = fopen(filename, "r");
  367.     auto queue q = Qnil;
  368.     register node n;
  369.  
  370.     if (!fp)
  371.         return Vnil;
  372.     do {
  373.         n = readnode(fp);
  374.         if (!n)
  375.             break; /* EOF or error */
  376.         addtoqueue(&q, n);
  377.         noderelease(n);
  378.     } while (skipsp(fp) == '\n');
  379.     fclose(fp);
  380.     return (value)q;
  381. }
  382. #endif SAVEBUF
  383.